#include <keypad.h>
#include <Wire.h>
#include <LCDI2C4Bit.h>
#include <DS1307.h>
#include <avr/pgmspace.h>

#define ROWS 4
#define COLS 3

keypad kpd = keypad(ROWS, COLS);


int rtc[7];
char buf[5]; // "-2147483648\0"
int ADDR = 0x38;
byte rtcram[5];

/*
;Connect the following pins from MCP23008 to LCD
 ;
 ;P0 - D4
 ;P1 - D5
 ;P2 - D6
 ;P3 - D7
 ;P4 - RS
 ;P5 - RW (not used, set to 0 to ground for write)
 ;P6 - Bl (backlight switch)
 ;P7 - E1;Connect the following pins from MCP23008 to LCD
 */

byte x = 0;
byte data = 1;
byte c;

LCDI2C4Bit lcd = LCDI2C4Bit(ADDR,2,40);


//                             "0123456789ABCDEF"
prog_char string_0[] PROGMEM = "The Time Is     ";   // "String 0" etc are strings to store - change to suit.
prog_char string_1[] PROGMEM = "Set The Time ";
prog_char string_2[] PROGMEM = "String 2";
prog_char string_3[] PROGMEM = "String 3";
prog_char string_4[] PROGMEM = "String 4";
prog_char string_5[] PROGMEM = "String 5";


// Then set up a table to refer to your strings.

PGM_P string_table[] PROGMEM =	   // change "string_table" name to suit
{   
  string_0,
  string_1,
  string_2,
  string_3,
  string_4,
  string_5 };

char lcdbuffer1[17]= "0123456789ABCDEF";    // make sure this is large enough for the largest string it must hold
char lcdbuffer2[17]= "0123456789ABCDEF";    // lcd display buffer

//char* lcdbuffer[]={"0123456789ABCDEF", "0123456789ABCDEF"};

char* lcdbuffer[]= {
  lcdbuffer1,
  lcdbuffer2
};






void setup()
{
  Serial.begin(9600);
  Wire.begin(); // join i2c bus (address optional for master)
  lcd.init();
  lcd.commandWrite(0x0F);
  //lcd.printIn("arnon");
  //WriteLCD(ADDR,'a');
  //LCDClear(ADDR);
  //WriteLCD(ADDR,'c');
  /* 
   lcd.cursorTo(1,0);
   lcd.printIn("1");
   lcd.cursorTo(2,0);
   lcd.printIn("2");
   lcd.cursorTo(3,0);
   lcd.printIn("3");
   */

  /*
  RTC.stop();
   RTC.set(DS1307_SEC,00);
   RTC.set(DS1307_MIN,30);
   RTC.set(DS1307_HR,15);
   RTC.set(DS1307_DOW,6);
   RTC.set(DS1307_DATE,5);
   RTC.set(DS1307_MTH,12);
   RTC.set(DS1307_YR,8);
   RTC.start();
   */
  strcpy_P(lcdbuffer[0], (char*)pgm_read_word(&(string_table[0]))); // Necessary casts and dereferencing, just copy. 
  Serial.println( lcdbuffer[0] );

  lcd.printIn(lcdbuffer[0]);

  kpd.init();
  digitalWrite(6, HIGH);
  digitalWrite(7, HIGH);
  digitalWrite(8, HIGH);
  digitalWrite(9, HIGH);
  Time();
}


void loop()
{
  Time();
  char key = kpd.get_key();
  if(key == '*') //Yes
  {
    lcd.cursorTo(0,0);
    strcpy_P(lcdbuffer[0], (char*)pgm_read_word(&(string_table[1]))); // Necessary casts and dereferencing, just copy. 
    lcd.printIn(lcdbuffer[0]);


    settime(1,0);
    savetime(1,0);
    setdate();
    setdow();


    lcd.cursorTo(0,0);
    strcpy_P(lcdbuffer[0], (char*)pgm_read_word(&(string_table[0]))); // Necessary casts and dereferencing, just copy. 
    lcd.printIn(lcdbuffer[0]);

  }
  else if(key == '#') //No
  {
    lcd.cursorTo(0,0);
    strcpy_P(lcdbuffer[0], (char*)pgm_read_word(&(string_table[2]))); // Necessary casts and dereferencing, just copy. 
    lcd.printIn(lcdbuffer[0]);


    rtcread(0x08);
    //printnum(rtcram[3],1,0);
    printnum(B11111111,1,0);
    Serial.println("setonoff");
    setonoff(3,1,0);
    rtcwrite(0x08);

  }
  else if(key == '0')
  {
    lcd.cursorTo(0,0);
    strcpy_P(lcdbuffer[0], (char*)pgm_read_word(&(string_table[3]))); // Necessary casts and dereferencing, just copy. 
    lcd.printIn(lcdbuffer[0]);
    int i;
    Serial.println("rtcread");
    for (i = 0 ; i<10 ;i++){
      rtcread(i*5);

    }
  }
}

void printnum(byte byt  ,int line_num, int x){
  //Serial.print(x);
  Serial.print(byt);
  //char str[9]= "12345678" ;
  int i;
  for (i = 0 ; i < 8 ;i++){
    if (byt & (1<<i)){
      lcdbuffer[line_num][x+i] = 49 + i;  //Turn into ascii and 1 to 8
      //Serial.println("on");
      //Serial.println(i);
    }
    else
    {
      lcdbuffer[line_num][x+i]=' ';
      //Serial.println("off");
      //Serial.println(i);
    }
    //Serial.println(lcdbuffer[line_num][x+i]);
  }
  refresh(0);
  //return str;
}


void setonoff(int i, int line_num, int x){
  while(1){
    char key = kpd.get_key();
    if (key >= '1' && key <= '8'){

      rtcram[i] ^= (1 << (cTI(key) - 1));  //toggle number on off


      //rtcram[i];
      printnum(rtcram[i],line_num,x);
    }
    else if (key == '0')
    {
      return;


    }


  }



}


void rtcread(int addr){
  Wire.beginTransmission(DS1307_CTRL_ID);
  Wire.send(addr);
  Wire.endTransmission();
  Wire.requestFrom(DS1307_CTRL_ID, 5);
  for(int i=0; i<5; i++)
  {
    // store data in raw bcd format
    rtcram[i]=Wire.receive();
    Serial.print(rtcram[i]);
  }
}



void rtcwrite(int addr){
  Wire.beginTransmission(DS1307_CTRL_ID);
  Wire.send(addr); // reset register pointer
  for(int i=0; i<5; i++)
  {
    Wire.send(rtcram[i]);
  }
  Wire.endTransmission();
}

void settime(int line_num, int x)
{
  char key = kpd.get_key();

  lcd.cursorTo(line_num,x);
  lcd.commandWrite(0x0D);
  lcd.cursorTo(line_num,x);

  //if(key != '\0')
  //{
  refresh(x);
  while(1){
    key = kpd.get_key();
    if (key >= '0' && key <= '2')
    {

      lcdbuffer[line_num][x] = (key);
      lcdbuffer[line_num][x+1] = ('0');

      refresh(x);
      //delay(200);     //debounce ?????
      lcd.cursorTo(line_num,x+1);
      //Serial.print('1');
      break;
    }
  }
  while(1){ // Hours
    key = kpd.get_key();
    if (key >= '1' && key <= '3')
    {
      lcdbuffer[line_num][x+1] = (key);
      refresh(x+3);
      break;
    }
    else if (key == '0')
    {
      if (lcdbuffer[line_num][x+0] == '1' || lcdbuffer[line_num][x+0] == '2')
      {
        lcdbuffer[line_num][x+1] = (key);
        refresh(x+3);
        break;


      }
    }
    else if (key >= '4' && key <= '9')
    {
      if (lcdbuffer[line_num][x+0] != '2')
      {
        lcdbuffer[line_num][x+1] = (key);
        refresh(x+3);
        break;


      }

    }
  }


  while(1){ // minutes
    key = kpd.get_key();
    if (key >= '0' && key <= '5')
    {
      lcdbuffer[line_num][x+3] = (key);
      refresh(x+4);
      break;
    }

  }
  //Serial.println("qq");
  //Serial.println(key);

  while(1){ // minutes 
    key = kpd.get_key();

    if (key >= '0' && key <= '9')
    {
      lcdbuffer[line_num][x+4] = (key);
      refresh(x+6);
      break;
      Serial.println(key);
    }
  }


  //char * thisChar = "A";
  //int a = atoi(lcdbuffer[1][12]); 

  Serial.println(key);
  refresh(x+0);
  //}   

  //Serial.println(key);

}


void savetime(int line_num, int x)
{
  RTC.get(rtc,true);
  RTC.stop();
  RTC.set(DS1307_SEC,00);
  RTC.set(DS1307_MIN,cTI(lcdbuffer[line_num][x+3])*10 + cTI(lcdbuffer[line_num][x+4]));
  RTC.set(DS1307_HR,cTI(lcdbuffer[line_num][x+0])*10 + cTI(lcdbuffer[line_num][x+1]));
  RTC.start();
}


void setdate()
{
  char key = kpd.get_key();
  lcd.cursorTo(1,0);
  lcd.commandWrite(0x0D);
  lcd.cursorTo(1,0);
  //if(key != '\0')
  //{

  refresh(6);


  while(1){ // days   tens
    key = kpd.get_key();

    if (key >= '0' && key <= '3')
    {
      lcdbuffer[1][6] = (key);
      refresh(7);
      break;
      Serial.println(key);
    }
  }

  while(1){ // days
    key = kpd.get_key();
    if (key == '1')
    {
      lcdbuffer[1][7] = (key);
      refresh(9);
      break;
      Serial.println(key);
    }
    else if (key >= '2' && key <= '9')
    {
      if (lcdbuffer[1][6] != '3')
      {
        lcdbuffer[1][7] = (key);
        refresh(9);
        break;
      }
    }
    else if (key == '0')
    {
      if (lcdbuffer[1][6] != '0' )
      {
        lcdbuffer[1][7] = (key);
        refresh(9);
        break;


      }
    }

  }




  while(1){ // months  tens
    key = kpd.get_key();
    if (key >= '0' && key <= '1')
    {
      lcdbuffer[1][9] = (key);
      refresh(10);
      break;
      Serial.println(key);
    }

  }

  while(1){ // months
    key = kpd.get_key();
    if (key == '1' || key == '2')
    {
      lcdbuffer[1][10] = (key);
      refresh(12);
      break;
      Serial.println(key);
    }
    else if (key >= '3' && key <= '9')
    {
      if (lcdbuffer[1][9] != '1')
      {
        lcdbuffer[1][10] = (key);
        refresh(12);
        break;
      }
    }
    else if (key == '0')
    {
      if (lcdbuffer[1][9] == '1' || lcdbuffer[1][9] == '2')
      {
        lcdbuffer[1][10] = (key);
        refresh(12);
        break;


      }
    }

  }


  while(1){ // years ten 
    key = kpd.get_key();

    if (key >= '0' && key <= '9')
    {
      lcdbuffer[1][12] = (key);
      refresh(13);
      break;
      Serial.println(key);
    }
  }

  while(1){ // years 
    key = kpd.get_key();

    if (key >= '0' && key <= '9')
    {
      lcdbuffer[1][13] = (key);
      refresh(0);
      break;
      Serial.println(key);
    }
  }

  //char * thisChar = "A";
  //int a = atoi(lcdbuffer[1][12]); 
  RTC.get(rtc,true);

  RTC.stop();

  RTC.set(DS1307_DATE,cTI(lcdbuffer[1][6])*10 + cTI(lcdbuffer[1][7]));
  RTC.set(DS1307_MTH,cTI(lcdbuffer[1][9])*10 + cTI(lcdbuffer[1][10]));
  Serial.print("set year");
  Serial.print(00);
  Serial.print(00);
  Serial.print(lcdbuffer[1][12]);
  Serial.print(00);
  Serial.print(00);
  Serial.print(cTI(lcdbuffer[1][12]));
  Serial.print(00);
  Serial.print(00);
  Serial.print(lcdbuffer[1][13]);
  Serial.print(00);
  Serial.print(00);
  Serial.print(cTI(lcdbuffer[1][13]));
  Serial.print(00);
  Serial.print(00);
  RTC.set(DS1307_YR,cTI(lcdbuffer[1][12])*10 + cTI(lcdbuffer[1][13]));
  RTC.start(); 

  Serial.println(key);
  refresh(0);
  //}   

  //Serial.println(key);

}


void setdow()
{
  refresh(15);
  char key = kpd.get_key();
  while(1){
    key = kpd.get_key();
    if (key >= '1' && key <= '7')
    {
      lcdbuffer[1][15] = (key);
      break;
    }
  }

  RTC.get(rtc,true);
  RTC.stop();
  RTC.set(DS1307_DOW,cTI(lcdbuffer[1][15]));
  RTC.start();

  refresh(0);


}








void Time()
{
  //delay(1000);
  RTC.get(rtc,true);

  lcd.cursorTo(1,0);
  lcd.commandWrite(0x0D);
  /*
    for(int i=0; i<7; i++)
   {
   Serial.print(rtc[i]);
   Serial.print(" ");
   }
   */
  /*
  for (int i = 0; i < 16; i++){
   lcdbuffer[1][i] = 'Q';
   }
   */

  //filllcd(itoa(rtc[DS1307_HR], buf , 10),0);
  filllcd(itoa(rtc[DS1307_HR], buf , 10),0);
  lcdbuffer[1][2] = (':');
  filllcd(itoa(rtc[DS1307_MIN], buf , 10),3);
  //lcdbuffer[1][5] = (':');
  //filllcd(itoa(rtc[DS1307_SEC], buf , 10),6);

  //Serial.println(lcdbuffer[1]);
  //Serial.println('n');

  lcdbuffer[1][5] =(' ');

  //Serial.println(lcdbuffer[1]);
  //Serial.println('b');


  filllcd(itoa(rtc[DS1307_DATE], buf , 10),6);

  //Serial.println(lcdbuffer[1]);
  //Serial.println('v');

  lcdbuffer[1][8] =('/');
  filllcd(itoa(rtc[DS1307_MTH], buf , 10),9);
  lcdbuffer[1][11] =(' ');
  filllcd(itoa(rtc[DS1307_YR], buf , 10),12);
  lcdbuffer[1][14] =(' ');

  //filllcd(itoa(rtc[DS1307_DOW], buf , 10),15);
  lcdbuffer[1][15] = itoa(rtc[DS1307_DOW], buf , 10)[0];
  //Serial.println(lcdbuffer[1]);
  //Serial.println('c');

  Serial.println("Time print");
  Serial.println(lcdbuffer[1]);                            //debug



  //Serial.println(lcdbuffer3);





  lcd.printIn(lcdbuffer[1]);
  //lcd.printIn(lcdbuffer3);

  //Serial.println(availableMemory());
}












void filllcd (char * date , int i){
  //Serial.println(i);
  if (date[1] == '\0'){
    lcdbuffer[1][i]= '0';
    lcdbuffer[1][i+1]= date[0];
  }
  else if (date[2] == '\0')
  {
    lcdbuffer[1][i]= date[0];
    lcdbuffer[1][i+1]= date[1];
  }
  else if (date[5] == '\0')
  {
    lcdbuffer[1][i]= date[0];
    lcdbuffer[1][i+1]= date[1];
    lcdbuffer[1][i+2]= date[2];
    lcdbuffer[1][i+3]= date[3];
  }
  //Serial.print(lcdbuffer[1][i]);
  //Serial.print(lcdbuffer[1][i+1]);
}



void refresh(int i){
  lcd.cursorTo(1,0);
  Serial.println("Refresh");
  Serial.println(lcdbuffer[1]);
  lcd.printIn(lcdbuffer[1]);

  lcd.cursorTo(1,i);
  lcd.commandWrite(0x0D);
}



int availableMemory() {
  int size = 1024;
  byte *buf;

  while ((buf = (byte *) malloc(--size)) == NULL)
    ;

  free(buf);

  return size;
}




int cTI (char i){
  return i - '0';
}


/*

 int cTI (char i){ //CHANGES FROM CHAR TO INT
 if(i == '0'){
 return 0;
 }
 else if(i == '1'){
 return 1;
 }
 else if(i == '2'){
 return 2;
 }
 else if(i == '3'){
 return 3;
 }
 else if(i == '4'){
 return 4;
 }
 else if(i == '5'){
 return 5;
 }
 else if(i == '6'){
 return 6;
 }
 else if(i == '7'){
 return 7;
 }
 else if(i == '8'){
 return 8;
 }
 else if(i == '9'){
 return 9;
 }
 return 0;
 }
 
 */
